/**
 * mapbox地图方法
 */
import { LineLayer, Mapbox, Scene } from '@antv/l7';
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import '@mapbox/mapbox-gl-draw/dist/mapbox-gl-draw.css';
import * as turf from '@turf/turf';
import axios from 'axios';
import _ from 'lodash-es';
import MapboxGL from 'mapbox-gl';
import 'mapbox-gl-plugin-layer-group';
// 绘图用的插件
import 'mapbox-gl/dist/mapbox-gl.css';
import proj4 from 'proj4';
import { BASE_GEOSERVER_URL } from '@/apis';
import { geo } from '@/pages/module-fire-system/fire-screen/geo';
import { useMapStore } from '@/stores';
import { DEFAULT_MAP_STATE, LAYERS_GROUP_ID, TD_CIA_URL, TD_IMG_URL } from './map-helper';
import { measureArea, closeMeasureArea } from './map-measure-area';
import { measureLineLength, closeMeasureLine } from './map-measure-distance';

let draw = null;
let popup = null;
let updatePoint = null;

const mapStore = useMapStore();

// * 保存地图实例
export let map = null;

/**
 *  初始化地图
 * @param {string} ID 容器id
 */

export function MAP_2D_INIT(ID) {
  map = new MapboxGL.Map({
    container: ID,
    style: {
      version: 8,
      glyphs: 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf',
      sources: {},
      layers: [],
    },
    center: [DEFAULT_MAP_STATE.longitude, DEFAULT_MAP_STATE.latitude],
    zoom: DEFAULT_MAP_STATE.zoom,
    bearing: DEFAULT_MAP_STATE.bearing,
    pitch: DEFAULT_MAP_STATE.pitch,

    minZoom: 4,
    maxZoom: 17,
  });

  //解决canvas渲染不正确
  map.on('styledata', function () {
    map.resize();
  });

  draw = new MapboxDraw({
    displayControlsDefault: false,
  });

  map.addControl(draw);

  let controls = map._controls;

  controls.forEach((control) => {
    if ('_updateLogo' in control) {
      map.removeControl(control);
    }

    // 去除attribute控件
    if ('_attribHTML' in control) {
      map.removeControl(control);
    }
  });

  map.touchZoomRotate.disableRotation();

  // 如果还需要禁用通过按键（如Shift + 拖动）来旋转地图，也可以添加以下代码
  map.keyboard.disable();

  //去除mapbox的logo
  map._logoControl && map.removeControl(map._logoControl);

  // map.addControl(
  //   new MapboxLanguage({
  //     defaultLanguage: 'zh-Hans',
  //   }),
  // );

  // * 添加图层组
  map.once('load', () => {
    // 添加所有的图层组（占位图层）
    _.map(LAYERS_GROUP_ID, (id) => {
      map.addLayerGroup(id);
    });
    // 添加底图

    CHANGE_MAPBOX_BASE_LAYER(map);
    CHANGE_MAPBOX_BASE_LABEL_LAYER(map);
    // * 地图初始化成功
    mapStore.INITIALIZE('2d');
  });

  window.map2d = map;

  return map;
}

export const SET_MAP_DRAG_ROTATE = (flag) => {
  map.dragRotate.disable();

  if (flag) {
    map.dragRotate.enable();
  }
};

/**
 * 获取map
 */
export const GET_MAPBOX_MAP = () => {
  return map;
};

/**
 * 添加antv/l7
 */
export const ADD_L7_MAP = (ID) => {
  const scene = new Scene({
    id: ID,
    map: new Mapbox({
      mapInstance: map,
    }),
    // 关闭默认 L7 Logo
    logoVisible: false,
  });

  scene.on('loaded', () => {
    const layer = new LineLayer({
      zIndex: 10,
    })
      .source(geo)
      .shape('wall')
      .size(20)
      .style({
        sourceColor: '#416c88',
        targetColor: 'rgba(64, 108, 136, 0.8)',
      });

    scene.addLayer(layer);
  });
};

/**
 * mapbox切换底图
 * @param { String } id 要切换的底图类型
 */
export const CHANGE_MAPBOX_BASE_LAYER = (MAP) => {
  const layerId = LAYERS_GROUP_ID.TD_BASE_MAP;
  let sources;

  // 移除原来图层
  REMOVE_MAPBOX_LAYER(layerId, MAP);

  sources = {
    TD_IMG: {
      id: layerId,
      type: 'raster',
      tiles: TD_IMG_URL,
      tileSize: 256,
    },
  };

  let layers = {
    id: layerId,
    type: 'raster',
    source: sources.TD_IMG,
  };

  MAP.addLayerToGroup(layerId, layers);
};

/**
 * mapbox切换标注
 * @param { String } id 要切换的底图类型
 */
export const CHANGE_MAPBOX_BASE_LABEL_LAYER = (MAP) => {
  const layerId = LAYERS_GROUP_ID.TD_BASE_LABEL_MAP;
  let sources;

  // 移除原来图层
  REMOVE_MAPBOX_LAYER(layerId, MAP);

  sources = {
    TD_IMG: {
      id: layerId,
      type: 'raster',
      tiles: TD_CIA_URL,
      tileSize: 256,
    },
  };

  let layers = {
    id: layerId,
    type: 'raster',
    source: sources.TD_IMG,
  };

  MAP.addLayerToGroup(layerId, layers);
};

/**
 * 切换地图样式(mapbox底图)
 * @param {*} data Mapbox地图样式
 * @param {*} MAP 地图实例
 */
export const MAP_STYLE_SWITCHER = (data, MAP) => {
  let token = 'pk.eyJ1IjoibXJ3YW5nMTIxMiIsImEiOiJjanQ1ZnF2M3QwNXliNDNvN3htMWYyODljIn0.eBdPKjo6n3odkn4thCjCxg';

  axios
    .get(`https://api.mapbox.com/styles/v1/${data}?access_token=${token}`)
    .then((result) => {
      const { data: newStyle } = result;
      const currentStyle = MAP.getStyle();

      newStyle.sources = Object.assign({}, currentStyle.sources, newStyle.sources);

      let Layers = newStyle.layers.filter((el) => {
        //去掉mapbox底图地名标注
        return !el.id.includes('-label');
      });

      const appLayers = currentStyle.layers.filter((el) => {
        return (
          (el.source &&
            el.source != 'mapbox://mapbox.satellite' &&
            el.source != 'mapbox' &&
            el.source != 'composite') ||
          el.id.includes('TD_BASE') ||
          el.id.includes('MAP_LAYER') ||
          el.id.includes('MEASURE_POINT')
        );
      });

      Layers = [...Layers, ...appLayers];
      newStyle.layers = Layers;
      MAP.setStyle(newStyle);
    })
    .catch((error) => {
      console.error(error);
    });
};

/**
 * 重置地图样式(切换为天地图底图时使用)
 * @param {*} MAP 地图实例
 */
export const MAP_STYLE_RESET = (MAP = map) => {
  const currentStyle = MAP.getStyle();

  const appLayers = currentStyle.layers.filter((el) => {
    return el.id.includes('TD_BASE') || el.id.includes('MAP_LAYER') || el.id.includes('MEASURE_POINT');
  });

  let newStyle = {};

  newStyle.layers = [...appLayers];
  newStyle.glyphs = 'mapbox://fonts/mapbox/{fontstack}/{range}.pbf';
  newStyle.version = 8;
  newStyle.sources = currentStyle.sources;

  delete newStyle.sprite;

  MAP.setStyle(newStyle);
};

/**
 * mapbox移除指定图层
 * @param {string} layerId 图层id
 */
export function REMOVE_MAPBOX_LAYER(layerId, MAP = map) {
  if (MAP?.getLayer(layerId) || MAP?.getLayer(layerId)) {
    MAP.removeLayer(layerId);
    MAP.removeSource(layerId);
  }
}

/**
 * 移除map_img
 */
export const REMOVE_MAP_IMG = (ID) => {
  if (map?.hasImage(ID)) {
    map?.removeImage(ID);
  }
};

/**
 * mapbox移除地图
 * @export
 */
export function REMOVE_2D_MAP() {
  window.map2d = null;

  map && map.remove();
  map = null;
}

/**
 * mapbox 跳转地图到指定位置和指定级别
 * @param {Object} latLang 经纬度数组
 * @param {Number} zoom 地图缩放级别
 */
export function MapBoxFlyTo(latLang, zoom) {
  map.flyTo({
    center: latLang, // 中心点坐标
    zoom: zoom,
  });
}

/**
 * mapbox 放大地图缩放级别
 */
export function MapBoxMagnifyZoom() {
  map.zoomIn();
}

/**
 * mapbox 缩小地图缩放级别
 */
export function MapBoxReduceZoom() {
  map.zoomOut();
}

/**
 * 切换3D
 */
export function mapTo3d(type) {
  if (type == '2d') {
    map.setProjection('globe');
    map.flyTo({
      pitch: 60,
      zoom: 12,
      bearing: 45,
      speed: 0.5,
    });
    map.setFog({
      color: 'rgba(66, 88, 106, 1.0)',
    });

    // Add some 3D terrain
    map.addSource('mapbox-dem', {
      type: 'raster-dem',
      url: 'mapbox://mapbox.terrain-rgb',
      tileSize: 512,
      maxzoom: 14,
    });
    map.setTerrain({
      source: 'mapbox-dem',
      exaggeration: 2,
    });
    window.requestAnimationFrame(frame);

    mapStore.CHANGE_MODE('3d');
  } else {
    if (map.getSource('mapbox-dem')) {
      map.setTerrain();
      map.removeSource('mapbox-dem');
    }

    map.setProjection('mercator');
    map.flyTo({
      pitch: 0,
      zoom: 9,
      bearing: 0,
      speed: 0.5,
    });

    mapStore.CHANGE_MODE('2d');
  }
}

let lastTime = 0.0;
let cycleTime = 0.0;
let night = true;

function frame(time) {
  const elapsedTime = (time - lastTime) / 1000.0;

  cycleTime += elapsedTime;

  if (cycleTime >= 50.0) {
    if (night) {
      map.setFog({
        color: 'rgba(216, 242 ,255, 1.0)',
      });
    } else {
      map.setFog({
        color: 'rgba(66, 88, 106, 1.0)',
      });
    }

    night = !night;
    cycleTime = 0.0;
  }

  lastTime = time;

  window.requestAnimationFrame(frame);
}

/**
 * 重置地图位置
 */
export const REST_MAP_FIT_BOUNDS = () => {
  const bbox = [90.52643750000135, 46.08512949598068, 79.97956250000101, 42.73136948754305];

  // 界线
  map?.fitBounds(
    [
      [bbox[0], bbox[1]],
      [bbox[2], bbox[3]],
    ],
    {
      padding: { top: 100, bottom: 100, left: 100, right: 100 },
      maxZoom: 7,
    },
  );
};

/**
 * ========查询数据=================
 */

/**
 * WFS服务(查询)
 */

/**
 * 点查询
 */
export const POINT_QUERY_FUN = async (val) => {
  try {
    const response = await axios.get(
      `${BASE_GEOSERVER_URL}/st_server_api/nikwfs/wfssev/?id=${val.id}&REQUEST=GetFeature&SERVICE=WFS&VERSION=1.1.0&TYPENAME=${val.TYPENAME}&MAXFEATURES=999999&SRSNAME=EPSG:4326&FILTER=INTERSECTS(EPSG:4326%3B+POINT(${val.lng} ${val.lat}))`,
    );

    return response.data;
  } catch (error) {
    console.error('Error fetching data:', error);

    const resultInfo = {
      features: [],
    };

    return resultInfo;
  }
};

/**
 * 空间框选查询
 */

export const SPACE_QUERY_FUN = async (val) => {
  try {
    const queryInfo = await axios.get(
      `${BASE_GEOSERVER_URL}/st_server_api/nikwfs/wfssev/?id=${
        val.id
      }&REQUEST=GetFeature&SERVICE=WFS&VERSION=1.1.0&TYPENAME=${
        val.TYPENAME
      }&MAXFEATURES=999999&SRSNAME=EPSG:4326&FILTER=${`INTERSECTS( EPSG:4326%3B+POLYGON((${String(
        _.chunk(_.flattenDeep(val.coordinates), 2)
          .map((item) => item.join(' '))
          .join(', '),
      )})))`}`,
    );

    if (queryInfo.data?.features?.length) {
      queryInfo.data?.features.map((item) => {
        const info = {
          tableLabel: [],
          table: {},
        };

        for (let propName in item.properties) {
          info.table[propName] = item.properties[propName];

          info.tableLabel.push(propName);
        }

        item.properties = info;
      });
    }

    return queryInfo.data;
  } catch (error) {
    console.error('Error fetching data:', error);

    const resultInfo = {
      features: [],
    };

    return resultInfo;
  }
};

/**
 * 条件查询
 */
export const GET_CONDITION_QUERY = async (val) => {
  try {
    const response = await axios.get(
      `${BASE_GEOSERVER_URL}/st_server_api/nikwfs/wfssev/?id=${val.id}&REQUEST=GetFeature&SERVICE=WFS&VERSION=1.1.0&TYPENAME=${val.TYPENAME}&MAXFEATURES=999999&SRSNAME=EPSG:4326&CQL_FILTER=${val.CQL_FILTER} `,
    );

    return response.data;
  } catch (error) {
    console.error('Error fetching data:', error);

    const resultInfo = {
      features: [],
    };

    return resultInfo;
  }
};

/**
 * 占地分析(范围)
 */
export const ZDFX_ANALYSES_RANGE = async (val) => {
  try {
    const queryInfo = await axios.get(
      `${BASE_GEOSERVER_URL}/st_server_api/nikwfs/wfssev/?id=${
        val.id
      }&REQUEST=GetFeature&SERVICE=WFS&VERSION=1.1.0&TYPENAME=${
        val.TYPENAME
      }&MAXFEATURES=999999&SRSNAME=EPSG:4326&FILTER=${`INTERSECTS( EPSG:4326%3B+POLYGON((${String(
        _.chunk(_.flattenDeep(val.coordinates), 2)
          .map((item) => item.join(' '))
          .join(', '),
      )})))`}`,
    );

    const allValues = queryInfo.data.features;
    const allFeatures = [];

    const rangeInfo = turf.polygon([val.coordinates[0]]);

    for (let i = 0; i < allValues.length; i++) {
      var intersection = turf.intersect(turf.featureCollection([allValues[i], rangeInfo]));

      if (intersection !== null) {
        const newVal = {
          ...intersection,
          properties: allValues[i].properties,
          id: allValues[i].id,
        };

        allFeatures.push(newVal);
      }
    }

    if (allFeatures.length) {
      allFeatures.map((item) => {
        const info = {
          tableLabel: [],
          table: {},
        };

        for (let propName in item.properties) {
          info.table[propName] = item.properties[propName];

          info.tableLabel.push(propName);
        }

        item.properties = info;
      });

      return turf.featureCollection(allFeatures);
    } else {
      const allFeatures_v = {
        features: [],
      };

      return allFeatures_v;
    }
  } catch (error) {
    console.error('Error fetching data:', error);

    const resultInfo = {
      features: [],
    };

    return resultInfo;
  }
};

/**
 * ========添加图层=================
 */
export const ADD_MAPBOX_BASE_LAYER_OBSCURATION = (MAP = map, xj) => {
  const layerId = LAYERS_GROUP_ID.TD_BASE_MAP_RIVER;
  // var bbox = turf.bbox(xj);
  // var bboxPolygon = turf.bboxPolygon(bbox);
  const res = turf.buffer(xj, 50, { units: 'miles' });
  let res1 = xj.features[0].geometry.coordinates[0][0];

  const layers = {
    //蒙版图层   //通过边界数据反选 达到挖洞效果
    id: 'mb',
    type: 'fill',
    source: {
      type: 'geojson',
      data: {
        type: 'Feature',
        geometry: {
          type: 'Polygon',
          coordinates: [
            [
              // 多边形外围 需要进行遮罩的点 这里是给世界地图加遮罩 所以是世界的四个端点
              [-180, 90],
              [180, 90],
              [180, -90],
              [-180, -90],
            ],
            // 第 1个孔 ,这个坐标数组就是你的边界坐标，用上面的世界坐标挖去这个边界坐标就能达到空心的效果，也就是蒙版
            res1,
          ],
        },
      },
    },
    paint: {
      'fill-color': 'rgba(8, 29, 45,1)',
      'fill-outline-color': 'rgb(57, 86, 102)',
    },
    layout: {
      visibility: 'visible',
    },
  };

  const bbox = turf.bbox(xj);

  const layer = {
    id: `${layerId}~1`,
    type: 'line',
    source: {
      type: 'geojson',
      data: xj.features[0],
    },
    layout: {},
    paint: {
      'line-color': 'rgb(207, 233, 255)',
      'line-width': 8,
      // 'line-dasharray': [5, 5],
    },
  };

  const layer1 = {
    id: layerId,
    type: 'fill',
    source: {
      type: 'geojson',
      data: res,
    },
    layout: {},
    paint: {
      'fill-opacity': 0.7,
      'fill-color': 'rgba(118, 142, 153,0.5)',
      'fill-outline-color': '#f8c021',
    },
  };

  map.addLayerToGroup(layerId, layer);
  map.addLayerToGroup(layerId, layer1);
  MAP.addLayerToGroup(layerId, layers);

  map.fitBounds(
    [
      [bbox[0], bbox[1]],
      [bbox[2], bbox[3]],
    ],
    {
      padding: { top: 100, bottom: 100, left: 100, right: 100 },
      // maxZoom: 13,
    },
  );
};

export function AGENCY_MAP_SERVER(item, el) {
  //地图服务代理格式化
  let regex = `${BASE_GEOSERVER_URL}/st_server_api/service/niktile/?x={x}&y={y}&z={z}&id=${item.id}&lyrname=${el.layerMeta.name}`;

  return regex;
}

// 高亮（实线）
export const High_Light_LAYER = async (layerId, values) => {
  if (values.length) {
    for (let i = 0; i < values.length; i++) {
      const layer = {
        id: `${layerId}~light${i}`,
        type: 'line',
        source: {
          type: 'geojson',
          data: values[i],
        },
        layout: {},
        paint: {
          'line-color': '#FF0000',
          'line-width': 3,
        },
      };

      map.addLayerToGroup(layerId, layer);

      // 范围
      const bbox = turf.bbox(values[i]);

      map.fitBounds(
        [
          [bbox[0], bbox[1]],
          [bbox[2], bbox[3]],
        ],
        {
          padding: { top: 100, bottom: 100, left: 100, right: 100 },
          // maxZoom: 13,
        },
      );
    }
  } else {
    const layer = {
      id: layerId,
      type: 'fill',
      source: {
        type: 'geojson',
        data: values,
      },
      layout: {},
      paint: {
        'fill-opacity': 0.7,
        'fill-color': '#e33e31',
        'fill-outline-color': '#f8c021',
      },
    };

    map.addLayerToGroup(layerId, layer);

    // 范围
    const bbox = turf.bbox(values);

    map.fitBounds(
      [
        [bbox[0], bbox[1]],
        [bbox[2], bbox[3]],
      ],
      {
        padding: { top: 100, bottom: 100, left: 100, right: 100 },
        // maxZoom: 14,
      },
    );
  }
};

// 高亮（虚线）
export const High_Light_Dotted_Line_LAYER = async (layerId, values) => {
  const bbox = turf.bbox(values);

  const layer = {
    id: `${layerId}~DottedLight`,
    type: 'line',
    source: {
      type: 'geojson',
      data: values,
    },
    layout: {},
    paint: {
      'line-color': '#FF0000',
      'line-width': 3,
      // 'line-dasharray': [5, 5],
    },
  };

  map.addLayerToGroup(layerId, layer);

  map.fitBounds(
    [
      [bbox[0], bbox[1]],
      [bbox[2], bbox[3]],
    ],
    {
      padding: { top: 100, bottom: 100, left: 100, right: 100 },
      // maxZoom: 13,
    },
  );
};

/**
 * 圆点高亮
 */
export const MAP_ADD_CIRCLE_BRIGHT = (POINT) => {
  const layer = {
    id: LAYERS_GROUP_ID.High_Light_RESULT_LAYER,
    type: 'circle',
    source: {
      type: 'geojson',
      data: {
        type: 'FeatureCollection',
        features: [
          {
            type: 'Feature',
            geometry: POINT.geometry,
          },
        ],
      },
    },
    paint: {
      // 绘制类属性
      'circle-opacity': 1, // 圆点的不透明度（可选，取值范围为 0 ~ 1，默认值为 1）
      'circle-radius': 5, // 圆点的半径（可选，值 >= 0，默认值为 5，单位：像素）
      'circle-color': '#e43c30', // 圆点的颜色（可选，默认值为 #000000）
    },
  };

  const allPoints = [];

  allPoints.push(turf.point(POINT.geometry.coordinates));

  // 特征集合
  const collection = turf.featureCollection(allPoints);
  // 范围
  const bbox = turf.bbox(collection);

  map.fitBounds(
    [
      [bbox[0], bbox[1]],
      [bbox[2], bbox[3]],
    ],
    {
      padding: { top: 100, bottom: 100, left: 100, right: 100 },
      // maxZoom: 18,
    },
  );

  map.addLayerToGroup(LAYERS_GROUP_ID.High_Light_RESULT_LAYER, layer);
};

/**
 * 将图层添加到MapBox地图中。
 * 如果图层已存在，则先移除该图层及其源。
 * 支持添加两种类型的图层：网格图层和普通栅格图层。
 *
 * @param {string} id 图层的唯一标识符。
 * @param {string} url 图层的瓦片URL。
 * @param {string} type 图层类型，可为'grid'或其他（决定是否添加到标注图层下）。
 */
export function ADD_LAYER_TO_MAP_BOX_MAP(id, layerValue) {
  if (map.getLayer(id) || map.getSource(id)) {
    map.removeLayer(id);
    map.removeSource(id);
  }

  // let layerId = '';

  // if (map.getLayer(LAYERS_GROUP_ID.TD_BASE_LABEL_MAP) || map.getSource(LAYERS_GROUP_ID.TD_BASE_LABEL_MAP)) {
  //   //是否有标注图层
  //   layerId = LAYERS_GROUP_ID.TD_BASE_LABEL_MAP;
  // }

  let source = {
    type: 'raster', // 类型（必填）
    tiles: [
      // 用于指定一个或多个切片数据源的请求地址（可选，和 TileJSON 中的 tiles 属性一致）
      layerValue.url,
    ],
    minzoom: 0, // 最小层级（可选，默认值为 0）
    maxzoom: 22, // 最大层级（可选，默认值为 22）
    attribution: '', // 属性信息（可选，用于地图展示时给用户看的一些信息）
  };
  let layer = {
    id: id,
    type: 'raster',
    source: source,
    minzoom: 0, // 最小层级（可选，取值范围为 0 ~ 24。当 style 的 zoom 小于此 minzoom 时，layer 将被隐藏）
    maxzoom: 24, // 最大层级（可选，取值范围为 0 ~ 24。当 style 的 zoom 大于此 maxzoom 时，layer 将被隐藏）
    layout: {
      // 布局类属性
      visibility: 'visible', // 可见性（可选，可选值为 none、visible，默认值为 visible）
    },
  };

  map.addLayerToGroup(id, layer);

  const { min_x, min_y, max_x, max_y } = layerValue.layerMeta.boundary_3857;
  let bbox = [
    [min_x, min_y],
    [max_x, max_y],
  ].map((item) => turf.toWgs84(turf.point(item)).geometry.coordinates);

  map.fitBounds(bbox, {
    padding: { top: 10, bottom: 25, left: 15, right: 15 },
  });
}

/**
 *热图图层
 */

export const MAP_ADD_HEAT_LAYER = (layerId, values) => {
  const features = turf.featureCollection(values);

  const bbox = turf.bbox(features);

  const dataHeat = {
    // 热力图数据
    type: 'geojson',
    data: features,
  };
  const layerHeat = {
    id: `${layerId}~heat`,
    type: 'heatmap',
    source: dataHeat,
    maxzoom: 15,
    paint: {
      //根据频率和属性大小增加热图权重
      'heatmap-weight': ['interpolate', ['linear'], ['get', 'mag'], 0, 0, 8, 1],
      //通过缩放级别增加热图颜色权重
      // heatmap-intensity是在heatmap-weight之上的乘数
      'heatmap-intensity': ['interpolate', ['linear'], ['zoom'], 0, 4, 13, 3],
      //热图的颜色渐变。Domain为0(低)~ 1(高)。
      //从0点开始颜色渐变，透明度为0
      //创建类似模糊的效果。
      'heatmap-color': [
        'interpolate',
        ['linear'],
        ['heatmap-density'],
        0,
        'rgba(33,102,172,0)',
        0.2,
        'rgb(103,169,207)',
        0.4,
        'rgb(209,229,240)',
        0.6,
        'rgb(253,219,199)',
        0.8,
        'rgb(239,138,98)',
        1,
        'rgb(178,24,43)',
      ],
      'heatmap-radius': ['interpolate', ['linear'], ['zoom'], 0, 4, 1, 4, 2, 8, 3, 16, 4, 25], //通过缩放级别调整热图半径

      'heatmap-opacity': ['interpolate', ['linear'], ['zoom'], 12, 1, 13, 0], //通过缩放级别从热图过渡到圆形图层
    },
  };
  const layerPoint = {
    id: `${layerId}~point`,

    type: 'circle',
    source: dataHeat,
    minzoom: 13,
    paint: {
      // 大小圆半径的地震震级和缩放级别
      'circle-radius': [
        'interpolate',
        ['linear'],
        ['zoom'],
        13,
        ['interpolate', ['linear'], ['get', 'mag'], 1, 1, 6, 4],
        21,
        ['interpolate', ['linear'], ['get', 'mag'], 1, 5, 6, 10],
      ],
      // 地震震级颜色圈
      'circle-color': [
        'interpolate',
        ['linear'],
        ['get', 'mag'],
        1,
        'rgba(33,102,172,0)',
        2,
        'rgb(103,169,207)',
        3,
        'rgb(209,229,240)',
        4,
        'rgb(253,219,199)',
        5,
        'rgb(239,138,98)',
        6,
        'rgb(178,24,43)',
      ],
      'circle-stroke-color': 'white',
      'circle-stroke-width': 1,

      // 通过缩放级别从热图过渡到圆层
      'circle-opacity': ['interpolate', ['linear'], ['zoom'], 7, 0, 8, 1],
    },
  };

  const layerSymbol = {
    id: `${layerId}~symbol`,

    type: 'symbol',
    source: dataHeat,
    minzoom: 13,
    layout: {
      visibility: 'visible',
      'text-field': ['get', 'name'],
      'text-justify': 'auto',
      'text-size': 20,
      'text-anchor': 'top',
      'text-letter-spacing': 0.1,
    },
    paint: {
      // 地震震级颜色圈
      'text-color': [
        'interpolate',
        ['linear'],
        ['get', 'mag'],
        1,
        'rgba(33,102,172,0)',
        2,
        'rgb(103,169,207)',
        3,
        'rgb(209,229,240)',
        4,
        'rgb(253,219,199)',
        5,
        'rgb(239,138,98)',
        6,
        'rgb(178,24,43)',
      ],
      'text-halo-color': 'white',
      'text-halo-width': 1,

      // 通过缩放级别从热图过渡到圆层
      'text-opacity': ['interpolate', ['linear'], ['zoom'], 7, 0, 8, 1],
    },
  };

  map.addLayerToGroup(layerId, layerHeat);
  map.addLayerToGroup(layerId, layerPoint);
  map.addLayerToGroup(layerId, layerSymbol);
  map.fitBounds(
    [
      [bbox[0], bbox[1]],
      [bbox[2], bbox[3]],
    ],
    {
      padding: { top: 100, bottom: 100, left: 100, right: 100 },
      maxZoom: 10,
    },
  );
};

/**
 * =========测量功能=========
 */
/**
 * 添加绘图工具
 */

export const ADD_DRAW = (option = {}) => {
  if (draw) {
    REMOVE_DRAW();
  }

  draw = new MapboxDraw({
    displayControlsDefault: false,

    ...option,
  });
  map.addControl(draw);
};

/**
 * 移除绘图工具
 */
export const REMOVE_DRAW = () => {
  if (!draw) return;

  draw.deleteAll();

  map.removeControl(draw);
  draw = null;
};

/**
 * 地图测量功能-清除
 */
export const MEASURE_CLEAR = () => {
  ADD_DRAW();

  if (popup) {
    popup.remove();
  }

  map.off('click', updatePoint);

  draw.deleteAll();
  REMOVE_MAPBOX_LAYER(LAYERS_GROUP_ID.MEASURE_POINT);
  REMOVE_MAP_IMG('pulsing-dot');
};

/**
 * 地图测量功能-测面
 */
export const MEASURE_AREA_V = () => {
  MEASURE_CLEAR();
  measureArea(map);
};

/**
 * 地图测量功能-测距
 */
export const MEASURE_LINE_V = () => {
  MEASURE_CLEAR();
  measureLineLength(map);
};

/**
 * 地图测量功能-清除
 */
export const MEASURE_CLEAR_V = () => {
  closeMeasureLine(map);
  closeMeasureArea(map);
  map.getCanvas().style.cursor = 'pointer';
};

/**
 * 地图测量功能-坐标测量
 */

export const MEASURE_POINT = () => {
  proj4.defs('EPSG:4546', '+proj=tmerc +lat_0=0 +lon_0=111 +k=1 +x_0=500000 +y_0=0 +ellps=GRS80 +units=m +no_defs');

  updatePoint = (e) => {
    REMOVE_MAPBOX_LAYER(LAYERS_GROUP_ID.MEASURE_POINT);
    REMOVE_MAP_IMG('pulsing-dot');

    POINT_MARKER(e.lngLat);

    const xy = proj4('EPSG:4546', [e.lngLat.lng, e.lngLat.lat]);

    popup = new MapboxGL.Popup({ anchor: 'bottom', offset: 15 })
      .setLngLat(e.lngLat)
      .setHTML(
        `<div style="width:172px;border-radius: 13px;text-align:left;font-size:14px">
        <div style="margin-bottom:8px">X坐标: ${xy[0].toFixed(5)}</div>
        <div >Y坐标: ${xy[1].toFixed(5)}</div>
        </div>`,
      )
      .addTo(map);

    if (popup) {
      popup.on('close', () => {
        REMOVE_MAPBOX_LAYER(LAYERS_GROUP_ID.MEASURE_POINT);
      });
    }
  };

  map.off('click', updatePoint);
  map.on('click', updatePoint);
};

export const POINT_MARKER = (values) => {
  const size = 100;

  const pulsingDot = {
    width: size,
    height: size,
    data: new Uint8Array(size * size * 4),

    onAdd: function () {
      const canvas = document.createElement('canvas');

      canvas.width = this.width;
      canvas.height = this.height;
      this.context = canvas.getContext('2d');
    },

    render: function () {
      const radius = (size / 2) * 0.3;
      const context = this.context;

      context.beginPath();
      context.arc(this.width / 2, this.height / 2, radius, 0, Math.PI * 2);
      context.fillStyle = '#ffffff';
      context.strokeStyle = 'rgba(255, 100, 100, 1)';
      context.lineWidth = 10;
      context.fill();
      context.stroke();

      this.data = context.getImageData(0, 0, this.width, this.height).data;

      map.triggerRepaint();

      return true;
    },
  };

  map.addImage('pulsing-dot', pulsingDot, { pixelRatio: 2 });

  const layer = {
    id: LAYERS_GROUP_ID.MEASURE_POINT,
    type: 'symbol',
    source: {
      type: 'geojson',
      data: {
        type: 'FeatureCollection',
        features: [
          {
            type: 'Feature',
            geometry: {
              type: 'Point',
              coordinates: [values.lng, values.lat],
            },
          },
        ],
      },
    },
    layout: {
      'icon-image': 'pulsing-dot',
    },
  };

  map.addLayerToGroup(LAYERS_GROUP_ID.MEASURE_POINT, layer);
};
